/////////////////////////////////////////////////////////////////////////////
// Name:        types.h
// Author:      Nicolay Giraldo
// Created:     15/12/05
// Copyright:   Nicolay Giraldo
/////////////////////////////////////////////////////////////////////////////

#ifndef __types_H__
#define __types_H__

enum type{
	t_value = 5000  ,
	t_nil           ,
	t_cons          ,
	t_nilcons       ,
	t_restarg       ,
	t_function      ,
	t_symbol        ,
	t_keyword       ,
	t_regexp        ,
	t_datetime      ,
	t_number        ,
	t_array         ,
	t_string        ,
	t_character     ,
	t_hashtable     ,
	t_package       ,
	t_real          ,
	t_complex       ,
	t_rational      ,
	t_floating      ,
	t_singlefloat   ,
	t_doublefloat   ,
	t_integer       ,
	t_ratio         ,
	t_fixnum        ,
	t_bignum        ,
	t_stream        ,
	t_randomstate   ,
	t_closclass     ,
	t_frame         ,
	t_thread        ,
	t_internal
};

template<byte count>
struct SVaPassNext{
    SVaPassNext<count-1> big;
    DWORD dw;
};
template<> struct SVaPassNext<0>{};
//SVaPassNext - is generator of structure of any size at compile time.

class CVaPassNext{
public:
    SVaPassNext<50> svapassnext;
    CVaPassNext(va_list & args){
		try{//to avoid access violation
			memcpy(&svapassnext, args, sizeof(svapassnext));
		} catch (...) {}
    }
};
#define va_pass(valist) CVaPassNext(valist).svapassnext

void MessBox(const wxChar *pszFormat,...);


enum gc_color 
{
	black ,
	grey  ,
	white
};

class value
{
	public:
	gc_color gc_status;
	virtual type getType() const = 0;//{return t_value;}
	virtual ~value() {};
};

class nil : public value
{
	public:
	type getType() const =0;//{return t_nil;}
};

class cons : public value
{
	public:
	value* car;
	value* cdr;
	cons() : car(NULL), cdr(NULL) {}
	cons(value* ncar, value* ncdr) : car(ncar), cdr(ncdr) {}
	~cons() { }
	// TODO: make the function recursive
//	void deleteContents() { wxDELETE(car); wxDELETE(cdr);}
	type getType() const {return t_cons;}
};

class string : public value
{
	public:
	wxString contents;
	string() {}
	string(wxString ncontents) : contents(ncontents) {}
	type getType() const {return t_string;}
};

class symbol : public value
{
	public:
	wxString name;
	bool iskeyword;
	cons* plist;
	symbol(wxString nname, bool iskeywordp = false) : name(nname), iskeyword(iskeywordp) {}
	type getType() const {return iskeyword ? t_keyword : t_symbol;}
};


inline value* trueval()
{
	return new symbol(_T("t"));
}


class regexp : public value
{
	public:
	wxRegEx contents;
	regexp() {}
	regexp(wxString ncontents) : contents(ncontents, wxRE_ADVANCED) {}
	type getType() const {return t_regexp;}
};

class datetime : public value
{
	public:
	wxDateTime contents;
	datetime() {}
	datetime(wxDateTime ncontents) : contents(ncontents) {}
	type getType() const {return t_datetime;}
};

class number : public value
{
	public:
	virtual number& operator + (const number& n) = 0;
//	virtual number& operator +=(const number& n) = 0;
//	virtual number& operator ++()                = 0;
	virtual number& operator - ()                = 0;
	virtual number& operator - (const number& n) = 0;
//	virtual number& operator -=(const number& n) = 0;
	virtual number& operator --()                = 0;
//	virtual number& operator % (const number& n) = 0;
//	virtual number& operator %=(const number& n) = 0;
	virtual number& operator * (const number& n) = 0;
//	virtual number& operator *=(const number& n) = 0;
	virtual number& operator / (const number& n) = 0;
//	virtual number& operator /=(const number& n) = 0;
	virtual value*  operator < (const number& n) = 0;
	virtual value*  operator <=(const number& n) = 0;
//	virtual value*  operator > (const number& n) = 0;
//	virtual value*  operator >=(const number& n) = 0;
//	virtual value*  operator ==(const number& n) = 0;
//	virtual value*  operator !=(const number& n) = 0;
//	virtual number& operator <<(const number& n) = 0;
//	virtual number& operator<<=(const number& n) = 0;
//	virtual number& operator >>(const number& n) = 0;
//	virtual number& operator>>=(const number& n) = 0;
//	virtual number& operator & (const number& n) = 0;
//	virtual number& operator &=(const number& n) = 0;
//	virtual number& operator ^ (const number& n) = 0;
//	virtual number& operator ^=(const number& n) = 0;
//	virtual number& operator | (const number& n) = 0;
//	virtual number& operator |=(const number& n) = 0;
	type getType() const = 0;//{return t_number;}
};

class character : public value
{
	public:
	wxChar mchar;
	type getType() const {return t_character;}
};

class hashtable : public value
{
	public:
	// yet to be implemented
	type getType() const {return t_hashtable;}
};

class package : public value
{
	public:
	wxString name;
	type getType() const {return t_package;}
};

class real : public number
{
	public:
	virtual number& operator + (const number& n) = 0;
//	virtual number& operator +=(const number& n) = 0;
//	virtual number& operator ++()                = 0;
	virtual number& operator - ()                = 0;
	virtual number& operator - (const number& n) = 0;
//	virtual number& operator -=(const number& n) = 0;
	virtual number& operator --()                = 0;
//	virtual number& operator % (const number& n) = 0;
//	virtual number& operator %=(const number& n) = 0;
	virtual number& operator * (const number& n) = 0;
//	virtual number& operator *=(const number& n) = 0;
	virtual number& operator / (const number& n) = 0;
//	virtual number& operator /=(const number& n) = 0;
	virtual value*  operator < (const number& n) = 0;
	virtual value*  operator <=(const number& n) = 0;
//	virtual value*  operator > (const number& n) = 0;
//	virtual value*  operator >=(const number& n) = 0;
//	virtual value*  operator ==(const number& n) = 0;
//	virtual value*  operator !=(const number& n) = 0;
//	virtual number& operator <<(const number& n) = 0;
//	virtual number& operator<<=(const number& n) = 0;
//	virtual number& operator >>(const number& n) = 0;
//	virtual number& operator>>=(const number& n) = 0;
//	virtual number& operator & (const number& n) = 0;
//	virtual number& operator &=(const number& n) = 0;
//	virtual number& operator ^ (const number& n) = 0;
//	virtual number& operator ^=(const number& n) = 0;
//	virtual number& operator | (const number& n) = 0;
//	virtual number& operator |=(const number& n) = 0;
	type getType() const = 0;//{return t_real;}
};

class complex : public number
{
	public:
	real& realpart;
	real& imagpart;
	complex(real& r, real& i) : realpart(r), imagpart(i) {}
	type getType() const {return t_complex;}
};

class rational : public real
{
	public:
	virtual number& operator + (const number& n) = 0;
//	virtual number& operator +=(const number& n) = 0;
//	virtual number& operator ++()                = 0;
	virtual number& operator - ()                = 0;
	virtual number& operator - (const number& n) = 0;
//	virtual number& operator -=(const number& n) = 0;
	virtual number& operator --()                = 0;
//	virtual number& operator % (const number& n) = 0;
//	virtual number& operator %=(const number& n) = 0;
	virtual number& operator * (const number& n) = 0;
//	virtual number& operator *=(const number& n) = 0;
	virtual number& operator / (const number& n) = 0;
//	virtual number& operator /=(const number& n) = 0;
	virtual value*  operator < (const number& n) = 0;
	virtual value*  operator <=(const number& n) = 0;
//	virtual value*  operator > (const number& n) = 0;
//	virtual value*  operator >=(const number& n) = 0;
//	virtual value*  operator ==(const number& n) = 0;
//	virtual value*  operator !=(const number& n) = 0;
//	virtual number& operator <<(const number& n) = 0;
//	virtual number& operator<<=(const number& n) = 0;
//	virtual number& operator >>(const number& n) = 0;
//	virtual number& operator>>=(const number& n) = 0;
//	virtual number& operator & (const number& n) = 0;
//	virtual number& operator &=(const number& n) = 0;
//	virtual number& operator ^ (const number& n) = 0;
//	virtual number& operator ^=(const number& n) = 0;
//	virtual number& operator | (const number& n) = 0;
//	virtual number& operator |=(const number& n) = 0;
	type getType() const =0;//{return t_rational;}
};

class floating : public real
{
	public:
	virtual number& operator + (const number& n) = 0;
//	virtual number& operator +=(const number& n) = 0;
//	virtual number& operator ++()                = 0;
	virtual number& operator - ()                = 0;
	virtual number& operator - (const number& n) = 0;
//	virtual number& operator -=(const number& n) = 0;
	virtual number& operator --()                = 0;
//	virtual number& operator % (const number& n) = 0;
//	virtual number& operator %=(const number& n) = 0;
	virtual number& operator * (const number& n) = 0;
//	virtual number& operator *=(const number& n) = 0;
	virtual number& operator / (const number& n) = 0;
//	virtual number& operator /=(const number& n) = 0;
	virtual value*  operator < (const number& n) = 0;
	virtual value*  operator <=(const number& n) = 0;
//	virtual value*  operator > (const number& n) = 0;
//	virtual value*  operator >=(const number& n) = 0;
//	virtual value*  operator ==(const number& n) = 0;
//	virtual value*  operator !=(const number& n) = 0;
//	virtual number& operator <<(const number& n) = 0;
//	virtual number& operator<<=(const number& n) = 0;
//	virtual number& operator >>(const number& n) = 0;
//	virtual number& operator>>=(const number& n) = 0;
//	virtual number& operator & (const number& n) = 0;
//	virtual number& operator &=(const number& n) = 0;
//	virtual number& operator ^ (const number& n) = 0;
//	virtual number& operator ^=(const number& n) = 0;
//	virtual number& operator | (const number& n) = 0;
//	virtual number& operator |=(const number& n) = 0;
	type getType() const=0;//{return t_floating;}
};

class singlefloat : public floating
{
	public:
	wxFloat32 num;
	singlefloat() : num(0) {}
	singlefloat(wxFloat32 n) : num(n) {}
	singlefloat(const singlefloat& n)  : num(n.num) {}
	singlefloat(const number& n);
	number& operator +  (const number& n);
//	number& operator += (const number& n);
	number& operator ++ ()               ;
	number& operator -  ()               ;
	number& operator -  (const number& n);
	number& operator -- ()               ;
	number& operator *  (const number& n);
//	number& operator *= (const number& n);
	number& operator /  (const number& n);
//	number& operator /= (const number& n);
	value*  operator <  (const number& n);
	value*  operator <= (const number& n);
	type getType() const {return t_singlefloat;}
};


class doublefloat: public floating
{
	public:
	wxFloat64 num;
	doublefloat() : num(0) {}
	doublefloat(wxFloat64 n) : num(n) {}
	doublefloat(const doublefloat& n)  : num(n.num) {}
	doublefloat(const number& n);
	number& operator +  (const number& n);
//	number& operator += (const number& n);
	number& operator ++ ()               ;
	number& operator -  ()               ;
	number& operator -  (const number& n);
	number& operator -- ()               ;
	number& operator *  (const number& n);
//	number& operator *= (const number& n);
	number& operator /  (const number& n);
//	number& operator /= (const number& n);
	value*  operator <  (const number& n);
	value*  operator <= (const number& n);
	type getType() const {return t_doublefloat;}
};


class integer : public rational
{
	public:
	virtual number& operator + (const number& n) = 0;
//	virtual number& operator +=(const number& n) = 0;
//	virtual number& operator ++()                = 0;
	virtual number& operator - ()                = 0;
	virtual number& operator - (const number& n) = 0;
//	virtual number& operator -=(const number& n) = 0;
	virtual number& operator --()                = 0;
//	virtual number& operator % (const number& n) = 0;
//	virtual number& operator %=(const number& n) = 0;
	virtual number& operator * (const number& n) = 0;
//	virtual number& operator *=(const number& n) = 0;
	virtual number& operator / (const number& n) = 0;
//	virtual number& operator /=(const number& n) = 0;
	virtual value*  operator < (const number& n) = 0;
	virtual value*  operator <=(const number& n) = 0;
//	virtual value*  operator > (const number& n) = 0;
//	virtual value*  operator >=(const number& n) = 0;
//	virtual value*  operator ==(const number& n) = 0;
//	virtual value*  operator !=(const number& n) = 0;
//	virtual number& operator <<(const number& n) = 0;
//	virtual number& operator<<=(const number& n) = 0;
//	virtual number& operator >>(const number& n) = 0;
//	virtual number& operator>>=(const number& n) = 0;
//	virtual number& operator & (const number& n) = 0;
//	virtual number& operator &=(const number& n) = 0;
//	virtual number& operator ^ (const number& n) = 0;
//	virtual number& operator ^=(const number& n) = 0;
//	virtual number& operator | (const number& n) = 0;
//	virtual number& operator |=(const number& n) = 0;
	type getType() const =0;//{return t_integer;}
};

class fixnum : public integer
{
	public:
	wxInt32 num;
	static wxInt32 most_positive_fixnum;
	static wxInt32 most_negative_fixnum;
	fixnum() : num(0) {}
	fixnum(wxInt32 n) : num(n) {}
	fixnum(const fixnum& n)  : num(n.num) {}
	fixnum(const number& n);
	number& operator +  (const number& n);
	number& operator -  ()               ;
	number& operator -  (const number& n);
	number& operator -- ()               ;
	number& operator *  (const number& n);
//	number& operator *= (const number& n);
	number& operator /  (const number& n);
//	number& operator /= (const number& n);
	value*  operator <  (const number& n);
	value*  operator <= (const number& n);
	fixnum* gcd (const fixnum* n);
	type getType() const {return t_fixnum;}
};


//#define MOST_POSITIVE_FIXNUM		2147483647
//#define MOST_NEGATIVE_FIXNUM		(-MOST_POSITIVE_FIXNUM-1)


extern const wxChar* mp_sw_rmap;

class bignum : public integer
{
	public:
	mp_int num;
	static bignum least_positive_bignum;
	static bignum least_negative_bignum;
	static bignum most_positive_fixnum;
	static bignum most_negative_fixnum;
	integer& chkmag();
	int status;
	bignum() { status = mp_init(&num); }
	bignum(const bignum& n) { status =  mp_init_copy(&num, &(((bignum&)(n)).num)); }
	bignum(const wxInt32 n);
	~bignum() { mp_clear(&num); }
	int read(wxString& source, int radix);
	int write(wxString& target, int radix);
	number& operator +  (const number& n);
	number& operator -  ()               ;
	number& operator -  (const number& n);
	number& operator -- ()               ;
	number& operator *  (const number& n);
//	number& operator *= (const number& n);
	number& operator /  (const number& n);
//	number& operator /= (const number& n);
	value*  operator <  (const number& n);
	value*  operator <= (const number& n);
	bignum* gcd (const bignum* n);
	bignum* gcd (const fixnum* n);
	type getType() const {return t_bignum;}
};


class ratio : public rational
{
	public:
	integer* numerator;
	integer* denominator;
	ratio(integer&, integer&);
	ratio(ratio& cc);
	ratio* reciprocal();
	number& operator +  (const number& n);
//	number& operator += (const number& n);
	number& operator ++ ()               ;
	number& operator -  ()               ;
	number& operator -  (const number& n);
	number& operator -- ()               ;
	number& operator *  (const number& n);
//	number& operator *= (const number& n);
	number& operator /  (const number& n);
//	number& operator /= (const number& n);
	value*  operator <  (const number& n);
	value*  operator <= (const number& n);
	void adjustgcd();
	rational& chkdenom();
	type getType() const {return t_ratio;}
};


class stream : public value
{
	public:
	wxStreamBuffer* v_stream;
	wxStreamBase* b_stream;
	stream() {}
	type getType() const {return t_stream;}
};

class randomstate : public value
{
	public:
	wxObject state;
	type getType() const {return t_randomstate;}
};


class closclass : public value
{
	public:
	wxString classtype;
	type getType() const {return t_closclass;}
};


union internalfunctionptr
{
	value* (*f00) ();
	value* (*f01) (value*);
	value* (*f02) (value*, value*);
	value* (*f03) (value*, value*, value*);
	value* (*f04) (value*, value*, value*, value*);
	value* (*f05) (value*, value*, value*, value*, value*);
	value* (*f06) (value*, value*, value*, value*, value*, value*);
	value* (*f07) (value*, value*, value*, value*, value*, value*, value*);
	value* (*f08) (value*, value*, value*, value*, value*, value*, value*, value*);
	value* (*f09) (value*, value*, value*, value*, value*, value*, value*, value*, value*);
	value* (*f10) (value*, value*, value*, value*, value*, value*, value*, value*, value*, value*);
	value* (*f11) (value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*);
	value* (*f12) (value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*);
	value* (*f13) (value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*);
	value* (*f14) (value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*);
	value* (*f15) (value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*);
	value* (*f16) (value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*);
	value* (*f17) (value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*);
	value* (*f18) (value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*);
	value* (*f19) (value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*);
	value* (*f20) (value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*);
	value* (*f21) (value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*);
	value* (*f22) (value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*);
	value* (*f23) (value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*);
	value* (*f24) (value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*);
	value* (*f25) (value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*);
	value* (*f26) (value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*);
	value* (*f27) (value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*);
	value* (*f28) (value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*);
	value* (*f29) (value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*);
	value* (*f30) (value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*);
	value* (*f31) (value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*);
	value* (*f32) (value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*);
	value* (*f33) (value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*);
	value* (*f34) (value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*);
	value* (*f35) (value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*);
	value* (*f36) (value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*);
	value* (*f37) (value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*);
	value* (*f38) (value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*);
	value* (*f39) (value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*);
	value* (*f40) (value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*);
	value* (*f41) (value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*);
	value* (*f42) (value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*);
	value* (*f43) (value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*);
	value* (*f44) (value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*);
	value* (*f45) (value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*);
	value* (*f46) (value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*);
	value* (*f47) (value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*);
	value* (*f48) (value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*);
	value* (*f49) (value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*);
	value* (*f50) (value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*, value*);
};


enum functiontype
{
	f_systemfunction  ,
	f_function        ,
	f_genericfunction ,
	f_method          ,
	f_closure         ,
	f_macro           ,
	f_specialop       ,
	f_invalid
};



enum parameterspec
{
	p_required      ,
	p_optional      ,
	p_supplied      ,
	p_rest          ,
	p_body          ,
	p_keyword       ,
	p_symbol        ,
	p_aux
};

class parameter : public value
{
	public:
	type ptype;
	parameterspec paramspec;
	cons* init_form;
	symbol name;
	bool supplied;
	parameter() : paramspec(p_required), name(_T("")) {}
	type getType() const {return t_internal;}
};

WX_DEFINE_ARRAY_PTR(value*    , valueArray    );
WX_DEFINE_ARRAY_PTR(parameter*, parameterArray);

class array : public value
{
	public:
	valueArray contents;
	array() {}
//	array(valarray ncontents) : contents(ncontents) {}
	type getType() const {return t_array;}
};

class internalfunction
{
	public:
	functiontype ftype;
	wxString docstring;
	valueArray paramvalues;
	parameterArray paramspecifiers;
	valueArray extravaluesreturned;
	unsigned int numparams;
	unsigned int reqparams;
	bool multiplevalreturn;
	bool allow_other_keys;
	bool has_required_args;
	bool has_optional_args;
	bool has_rest_args;
	bool has_keyword_args;
	bool has_aux_args;
	union internalfunctionptr funptr;
	bool checkParamTypes();
	internalfunction() : ftype(f_invalid), numparams(0), reqparams(0), multiplevalreturn(false), allow_other_keys(false), has_required_args(false), has_optional_args(false), has_rest_args(false), has_keyword_args(false), has_aux_args(false) {}
	value* CallSystemFun();
	value* Call();
	cons* definition;
};


class function : public value
{
	public:
	internalfunction* mfunction;
	type getType() const {return t_function;}
};


WX_DECLARE_STRING_HASH_MAP( value*          , valueMap    );
WX_DECLARE_STRING_HASH_MAP( internalfunction, functionMap );


class globalenvironment
{
	public:
	valueMap    vmap;
	functionMap fmap;
};

enum specialforms
{
	sf_block,
	sf_cont_capture,
	sf_cont_graft,
	sf_cont_return,
	sf_catch,
	sf_declare,
	sf_eval_when,
	sf_flet,
	sf_function,
	sf_go,
	sf_if,
	sf_labels,
	sf_let,
	sf_let_star,
	sf_load_time_value,
	sf_locally,
	sf_macrolet,
	sf_multiple_value_call,
	sf_multiple_value_prog1,
	sf_progn,
	sf_progv,
	sf_quote,
	sf_return_from,
	sf_setq,
	sf_symbol_macrolet,
	sf_tagbody,
	sf_the,
	sf_throw,
	sf_unwind_protect,
	sf_notsf
};

class evalframe
{
	public:
	bool arglistfilled; // if args were already extracted from expr
	bool isspecialform;
	bool isfunction;
	bool deletable;
	specialforms specialform;
	valueArray pargs; // args passed
	valueArray eargs; // args passed and evaluated
	value* fslot;
	value* expr;
	value* result;
	unsigned int nresults; // # results
	unsigned int n; // # args passed
	unsigned int i; // # args already evaluated
	valueArray extraresults;
	internalfunction* mfunction;
	evalframe* parentframe;
	evalframe() : arglistfilled(false), isspecialform(false), isfunction(false), deletable(true), specialform(sf_notsf), fslot(NULL), expr(NULL), result(NULL), nresults(1), n(0), i(0), mfunction(NULL), parentframe(NULL) { }
	evalframe(evalframe* nparentframe) : arglistfilled(false), isspecialform(false), isfunction(false), deletable(true), specialform(sf_notsf), fslot(NULL), expr(NULL), result(NULL), nresults(1), n(0), i(0), mfunction(NULL), parentframe(nparentframe) { }
};


class thread : public value, public wxThread
{
	public:
	thread(wxThreadKind kind = wxTHREAD_JOINABLE) : wxThread(kind) {}
	evalframe tevalframe;
	void* Entry() {return NULL;}
	type getType() const {return t_thread;}
};


#endif
